package com.platform.file.utils;

import com.platform.common.core.exception.file.FileNameLengthLimitExceededException;
import com.platform.common.core.exception.file.FileSizeLimitExceededException;
import com.platform.common.core.exception.file.InvalidExtensionException;
import com.platform.common.core.utils.DateUtils;
import com.platform.common.core.utils.StringUtils;
import com.platform.common.core.utils.file.FileTypeUtils;
import com.platform.common.core.utils.file.MimeTypeUtils;
import com.platform.common.core.utils.uuid.Seq;
import com.platform.common.security.utils.AESUtil_SC;
import com.platform.file.constant.SysFileConstants;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.io.IOUtils;
import org.apache.pdfbox.io.RandomAccessFile;
import org.apache.pdfbox.pdfparser.PDFParser;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPageTree;
import org.springframework.web.multipart.MultipartFile;

import java.io.*;
import java.nio.file.Paths;
import java.util.Objects;
import java.util.UUID;
import java.util.stream.IntStream;

/**
 * 文件上传工具类
 *
 * @author mbtec
 */
@Slf4j
public class FileUploadUtils
{
    /**
     * 默认大小 50M
     */
    public static final long DEFAULT_MAX_SIZE = 50 * 1024 * 1024;

    /**
     * 默认的文件名最大长度 100
     */
    public static final int DEFAULT_FILE_NAME_LENGTH = 100;

    /**
     * 根据文件路径上传
     *
     * @param baseDir 相对应用的基目录
     * @param file 上传的文件
     * @return 文件名称
     * @throws IOException
     */
    public static final String upload(String baseDir, MultipartFile file) throws IOException
    {
        try
        {
            return upload(baseDir, file, MimeTypeUtils.DEFAULT_ALLOWED_EXTENSION);
        }
        catch (Exception e)
        {
            throw new IOException(e.getMessage(), e);
        }
    }
    public static final String uploadTwo(String baseDir, MultipartFile file) throws IOException
    {
        try
        {
            return uploadTwo(baseDir, file, MimeTypeUtils.DEFAULT_ALLOWED_EXTENSION);
        }
        catch (Exception e)
        {
            throw new IOException(e.getMessage(), e);
        }
    }

    /**
     * 文件上传
     *
     * @param baseDir 相对应用的基目录
     * @param file 上传的文件
     * @param allowedExtension 上传文件类型
     * @return 返回上传成功的文件名
     * @throws FileSizeLimitExceededException 如果超出最大大小
     * @throws FileNameLengthLimitExceededException 文件名太长
     * @throws IOException 比如读写文件出错时
     * @throws InvalidExtensionException 文件校验异常
     */
    public static final String upload(String baseDir, MultipartFile file, String[] allowedExtension)
            throws FileSizeLimitExceededException, IOException, FileNameLengthLimitExceededException,
            InvalidExtensionException
    {
        int fileNamelength = Objects.requireNonNull(file.getOriginalFilename()).length();
        if (fileNamelength > FileUploadUtils.DEFAULT_FILE_NAME_LENGTH)
        {
            throw new FileNameLengthLimitExceededException(FileUploadUtils.DEFAULT_FILE_NAME_LENGTH);
        }

        assertAllowed(file, allowedExtension);

        String fileName = extractFilename(file);

        String absPath = getAbsoluteFile(baseDir, fileName).getAbsolutePath();
        file.transferTo(Paths.get(absPath));
        return getPathFileName(fileName);
    }

    public static final String uploadTwo(String baseDir, MultipartFile file, String[] allowedExtension)
            throws FileSizeLimitExceededException, IOException, FileNameLengthLimitExceededException,
            InvalidExtensionException
    {
        int fileNamelength = Objects.requireNonNull(file.getOriginalFilename()).length();
        if (fileNamelength > FileUploadUtils.DEFAULT_FILE_NAME_LENGTH)
        {
            throw new FileNameLengthLimitExceededException(FileUploadUtils.DEFAULT_FILE_NAME_LENGTH);
        }

        assertAllowed(file, allowedExtension);

        String fileName = file.getOriginalFilename();

        String absPath = getAbsoluteFile(baseDir, fileName).getAbsolutePath();
        file.transferTo(Paths.get(absPath));
        return getPathFileName(fileName);
    }

    /**
     * 编码文件名
     */
    public static final String extractFilename(MultipartFile file)
    {
        return StringUtils.format("{}/{}_{}.{}", DateUtils.datePath(),
                FilenameUtils.getBaseName(file.getOriginalFilename()), Seq.getId(Seq.uploadSeqType), FileTypeUtils.getExtension(file));
    }
    /**
     * 编码文件名
     */
    public static final String extractFilenameTwo(MultipartFile file)
    {
        return StringUtils.format("{}/{}_{}.{}", DateUtils.datePath(),
                FilenameUtils.getBaseName(file.getOriginalFilename()), FileTypeUtils.getExtension(file));
    }

    private static final File getAbsoluteFile(String uploadDir, String fileName) throws IOException
    {
        File desc = new File(uploadDir + File.separator + fileName);

        if (!desc.exists())
        {
            if (!desc.getParentFile().exists())
            {
                desc.getParentFile().mkdirs();
            }
        }
        return desc.isAbsolute() ? desc : desc.getAbsoluteFile();
    }

    private static final String getPathFileName(String fileName) throws IOException
    {
        String pathFileName = "/" + fileName;
        return pathFileName;
    }

    /**
     * 文件大小校验
     *
     * @param file 上传的文件
     * @throws FileSizeLimitExceededException 如果超出最大大小
     * @throws InvalidExtensionException 文件校验异常
     */
    public static final void assertAllowed(MultipartFile file, String[] allowedExtension)
            throws FileSizeLimitExceededException, InvalidExtensionException
    {
        long size = file.getSize();
        if (size > DEFAULT_MAX_SIZE)
        {
            throw new FileSizeLimitExceededException(DEFAULT_MAX_SIZE / 1024 / 1024);
        }

        String fileName = file.getOriginalFilename();
        String extension = FileTypeUtils.getExtension(file);
        if (allowedExtension != null && !isAllowedExtension(extension, allowedExtension))
        {
            if (allowedExtension == MimeTypeUtils.IMAGE_EXTENSION)
            {
                throw new InvalidExtensionException.InvalidImageExtensionException(allowedExtension, extension,
                        fileName);
            }
            else if (allowedExtension == MimeTypeUtils.FLASH_EXTENSION)
            {
                throw new InvalidExtensionException.InvalidFlashExtensionException(allowedExtension, extension,
                        fileName);
            }
            else if (allowedExtension == MimeTypeUtils.MEDIA_EXTENSION)
            {
                throw new InvalidExtensionException.InvalidMediaExtensionException(allowedExtension, extension,
                        fileName);
            }
            else if (allowedExtension == MimeTypeUtils.VIDEO_EXTENSION)
            {
                throw new InvalidExtensionException.InvalidVideoExtensionException(allowedExtension, extension,
                        fileName);
            }
            else
            {
                throw new InvalidExtensionException(allowedExtension, extension, fileName);
            }
        }
    }

    /**
     * 判断MIME类型是否是允许的MIME类型
     *
     * @param extension 上传文件类型
     * @param allowedExtension 允许上传文件类型
     * @return true/false
     */
    public static final boolean isAllowedExtension(String extension, String[] allowedExtension)
    {
        for (String str : allowedExtension)
        {
            if (str.equalsIgnoreCase(extension))
            {
                return true;
            }
        }
        return false;
    }
    /**
     * 提取文件后缀（不含点）
     * @param fileName 文件名（如 "example.txt" 或 "path/to/file.jpg"）
     * @return 文件后缀（小写，如 "txt"、"jpg"），若无后缀返回空字符串
     */
    public static String getExtension(String fileName) {
        if (fileName == null || fileName.isEmpty()) {
            return "";
        }

        // 处理可能包含路径的情况（提取最后一部分作为文件名）
        String namePart = fileName.contains("/")
                ? fileName.substring(fileName.lastIndexOf('/') + 1)
                : fileName;

        namePart = namePart.contains("\\")
                ? namePart.substring(namePart.lastIndexOf('\\') + 1)
                : namePart;

        // 处理文件名中的点（最后一个点之后的部分为后缀）
        int dotIndex = namePart.lastIndexOf('.');
        if (dotIndex == -1 || dotIndex == namePart.length() - 1) {
            return ""; // 无后缀或点在最后（如 ".gitignore" 或 "readme"）
        }

        // 提取后缀并转为小写
        return namePart.substring(dotIndex + 1).toLowerCase();
    }
    public static String getBucketName(String filename){
        if(StringUtils.isEmpty(filename)){
            return null;
        }
        if(!filename.contains("/")){
            return null;
        }
        int index = filename.indexOf("/");
        return filename.substring(0,index);
    }


    /**
     * 校验pdf文件是否包含js脚本
     **/
    public static boolean containsJavaScript(MultipartFile file)  {
        if (file== null || file.isEmpty()){
            return false;
        }
        // 文件后缀
        String fileName = file.getOriginalFilename();
        if (StringUtils.isEmpty(fileName)){
            log.error("文件信息异常！");
            return false;
        }
        String suffix = fileName.substring(fileName.lastIndexOf(".") + 1).toLowerCase();
        // 判断是否是pdf文件类型
        if (!StringUtils.equals(suffix, "pdf")) {
            return false;
        }
        File toFile = null;
        RandomAccessFile is = null;
        PDDocument document = null;
        try {
            toFile = multipartFileToFile(file);
            is = new RandomAccessFile(toFile, "r");
            PDFParser parser = new PDFParser(is);
            parser.parse();
            document = parser.getPDDocument();

            String CosName = document.getDocument().getTrailer().toString();
            if (CosName.contains("COSName{JavaScript}") || CosName.contains("COSName{JS}")) {
                return true;
            }

            PDPageTree pages = document.getPages();
            return IntStream.range(0, pages.getCount()).anyMatch(i -> {
                String pageContent = pages.get(i).getCOSObject().toString();
                return pageContent.contains("COSName{JS}") ||pageContent.contains("COSName{JavaScript}") ;
            });
        } catch (Exception e) {
            log.error("PDF效验异常：" + e.getMessage());
            return false;
        } finally {
            IOUtils.closeQuietly(is);
            if (document != null) {
                try {
                    document.close();
                } catch (IOException e) {
                    log.error("关闭PDF文档时出错：" + e.getMessage());
                }
            }
            if (toFile != null && toFile.exists()) {
                toFile.delete();  // 删除临时文件
            }
        }
    }



    /**
     * File转MultipartFile
     *
     * @param mulFile 文件对象
     * @return Multipart文件对象
     */
    public static File multipartFileToFile(MultipartFile mulFile) throws IOException {
        InputStream ins = mulFile.getInputStream();
        String fileName = mulFile.getOriginalFilename();
        String prefix = getFileNameNoSuffix(fileName) + UUID.randomUUID().toString();
        String suffix = "." + getSuffixNameName(fileName);
        File toFile = File.createTempFile(prefix, suffix);
        OutputStream os = new FileOutputStream(toFile);
        int bytesRead = 0;
        byte[] buffer = new byte[8192];
        while ((bytesRead = ins.read(buffer, 0, 8192)) != -1) {
            os.write(buffer, 0, bytesRead);
        }
        os.close();
        ins.close();
        return toFile;
    }


    /**
     * 获取不带扩展名的文件名
     */
    public static String getFileNameNoSuffix(String filename) {
        if ((filename != null) && (filename.length() > 0)) {
            int dot = filename.lastIndexOf('.');
            if ((dot > -1) && (dot < (filename.length()))) {
                return filename.substring(0, dot);
            }
        }
        return filename;
    }

    /**
     * 获取文件扩展名
     */
    public static String getSuffixNameName(String filename) {
        if ((filename != null) && (filename.length() > 0)) {
            int dot = filename.lastIndexOf('.');
            if ((dot > -1) && (dot < (filename.length() - 1))) {
                return filename.substring(dot + 1);
            }
        }
        return filename;
    }



    public static void main(String[] args) throws Exception {
        String path="files/public/platform-customsDeclaration/2023/08/07/103_1_20230807112029727_53906325480_报关单_20230807101600A826-1_20230807112032A088.jpg";
        String url= AESUtil_SC.encryptNoBase64(path,SysFileConstants.FILESECRET);
        System.out.println("加密 = " + url);
        //System.out.println("解密 = " + AESUtil_SC.decryptNoBase64("7247f1a1e8a7b5e975b1cf02b135f2cd13969aa1610c81e5a74d86c33543a9fc4528dcabb330443cc7db581e8467139420a728a7f114a60086bc417a4596d08b7c611f1dfcca835415fda4fa67f516b885012bb0cace1e028bf363056beccd63",SysFileConstants.FILESECRET));
        System.out.println("解密 = " + AESUtil_SC.decryptNoBase64("89e55a51b575a38668994f99b754f16acc55f7c5c118a1e369dab974ab5e8da69f8f136611fb234d2b9d92bcffee017715f8ba162a17eb184182c3fd8f9523fe4e0ddfe66894ead3ed8245a43896981c89fd935714370c61b0326c5ba7b97a4b3fed7f1516522602c95b584bcc214481",SysFileConstants.FILESECRET));


        //System.out.println(getBucketName("path"));
    }
}
